#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_bt_device.h"
#include "esp_gap_bt_api.h"
#include "esp_hf_client_api.h"
#include "hfp_app.h"
#include "alert_ctrl.h"
#include "my_nvs.h"

// 事件
const char *c_hf_evt_str_cn[] = {
    "事件:连接状态发生改变",              /*!< connection state changed event */
    "事件:音频连接状态发生改变",          /*!< audio connection state change event */
    "事件:声音识别状态发生改变",          /*!< voice recognition state changed */
    "事件:呼叫标志",                     /*!< call indication event */
    "事件:呼叫设置标志",                 /*!< call setup indication event */
    "事件:呼叫保持标志",                 /*!< call held indicator event */
    "事件:网络状态发生改变",              /*!< network state change event */
    "事件:信号强度标志",                 /*!< signal strength indication event */
    "事件:漫游状态标志",                 /*!< roaming status indication event */
    "事件:电池电平标志",                 /*!< battery level indication event */
    "事件:当前操作人名称",               /*!< current operator name event */
    "事件:响应保持",                    /*!< response and hold event */
    "事件:呼叫线路标志通知",             /*!< Calling Line Identification notification event */
    "事件:呼叫等待通知",                  /*!< call waiting notification */
    "事件:列出当前呼叫",                   /*!< listing current calls event */
    "事件:音量控制事件VOLUME_CONTROL_EVT", /*!< audio volume control event */
    "事件:音量控制事件AT_RESPONSE",        /*!< audio volume control event */
    "事件:订阅者信息",               /*!< subscriber information event */
    "事件:in-band铃声设置",              /*!< in-band ring tone settings */
    "事件:从AG请求的号码 LAST_VOICE_TAG_NUMBER_EVT", /*!< requested number from AG event */
    "事件:铃声指示",                      /*!< ring indication event */
};

// 连接状态
const char *c_connection_state_str[] = {
    "已断开连接", // disconnected
    "connecting",
    "已连接",    // connected
    "slc_connected",
    "disconnecting",
};

// esp_hf_client_audio_state_t
const char *c_audio_state_str[] = {
    "disconnected",
    "connecting",
    "connected",
    "connected_msbc",
};

/// esp_hf_vr_state_t
const char *c_vr_state_str[] = {
    "disabled",
    "enabled",
};

// 网络状态改变
const char *c_service_availability_status_str[] = {
    "不可用", // unavailable
    "可用", // available
};

// esp_hf_roaming_status_t
const char *c_roaming_status_str[] = {
    "否", // inactive
    "是", // active
};

// 呼叫状态
const char *c_call_str[] = {
    "无呼叫",    // NO call in progress
    "有呼叫",   // call in progress
};

// 呼叫设置
const char *c_call_setup_str[] = {
    "无", // NONE
    "呼入", // INCOMING
    "呼出", // OUTGOING_DIALING
    "呼出报警", // OUTGOING_ALERTING
};

// esp_hf_client_callheld_t
const char *c_call_held_str[] = {
    "无保持", // NONE held
    "保持并且活动", // Held and Active
    "保持", // Held
};

// esp_hf_response_and_hold_status_t
const char *c_resp_and_hold_str[] = {
    "HELD",
    "HELD ACCEPTED",
    "HELD REJECTED",
};

// esp_hf_client_call_direction_t
const char *c_call_dir_str[] = {
    "outgoing",
    "incoming",
};

// esp_hf_client_call_state_t
const char *c_call_state_str[] = {
    "active",
    "held",
    "dialing",
    "alerting",
    "incoming",
    "waiting",
    "held_by_resp_hold",
};

// esp_hf_current_call_mpty_type_t
const char *c_call_mpty_type_str[] = {
    "single",
    "multi",
};

// esp_hf_volume_control_target_t
const char *c_volume_control_target_str[] = {
    "SPEAKER",
    "MICROPHONE"
};

// esp_hf_at_response_code_t
const char *c_at_response_code_str[] = {
    "OK",
    "ERROR"
    "ERR_NO_CARRIER",
    "ERR_BUSY",
    "ERR_NO_ANSWER",
    "ERR_DELAYED",
    "ERR_BLACKLILSTED",
    "ERR_CME",
};

// esp_hf_subscriber_service_type_t
const char *c_subscriber_service_type_str[] = {
    "unknown",
    "voice",
    "fax",
};

// esp_hf_client_in_band_ring_state_t
const char *c_inband_ring_state_str[] = {
    "NOT provided",
    "Provided",
};

// 手机蓝牙MAC地址
static esp_bd_addr_t peer_addr = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static xQueueHandle task_queue = NULL;
static xTaskHandle task_handle = NULL;

// 发送通知事件
static bool hfp_app_send_event(uint8_t event)
{
    if (xQueueSend(task_queue, &event, 10 / portTICK_RATE_MS) != pdTRUE) {
        ESP_LOGE(BT_HF_TAG, "%s xQueue send failed", __func__);
        return false;
    }
    ESP_LOGI(BT_HF_TAG, "%s xQueue send complete", __func__);
    return true;
}

// HFP蓝牙事件回调
void bt_app_hf_client_cb(esp_hf_client_cb_event_t event, esp_hf_client_cb_param_t *param)
{
    if (event <= ESP_HF_CLIENT_RING_IND_EVT) {
        ESP_LOGI(BT_HF_TAG, "APP HFP event: %s", c_hf_evt_str_cn[event]);
    } else {
        ESP_LOGE(BT_HF_TAG, "APP HFP invalid event %d", event);
    }

    switch (event) {
        case ESP_HF_CLIENT_CONNECTION_STATE_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--connection state %s, peer feats 0x%x, chld_feats 0x%x",
                    c_connection_state_str[param->conn_stat.state],
                    param->conn_stat.peer_feat,
                    param->conn_stat.chld_feat);
            // 连接后保存mac地址, 并写入储存
            if(param->conn_stat.state == 0x03)
            {
                memcpy(peer_addr,param->conn_stat.remote_bda,ESP_BD_ADDR_LEN);
                my_nvs_write_mac(peer_addr);
            }
            else if(param->conn_stat.state == 0x00)     // 连接断开
            {
                alert_ctrl_send_event(ALERT_ENENT_BT_DISCONNWCT);
                // 发送一个蓝牙未连接消息
                hfp_app_send_event(0x00);
            }
            if(param->conn_stat.state == 0x02)      // 已连接
            {
                alert_ctrl_send_event(ALERT_ENENT_BT_CONNWCT);
                // 发送一个蓝牙已连接消息
                hfp_app_send_event(0x01);
            }
            break;
        }

        case ESP_HF_CLIENT_AUDIO_STATE_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--audio state %s",
                    c_audio_state_str[param->audio_stat.state]);
    // 若要打开宏需要在menuconfig里配置
    #if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI
            if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED ||
                param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_CONNECTED_MSBC) {
                esp_hf_client_register_data_callback(bt_app_hf_client_incoming_cb,
                                                    bt_app_hf_client_outgoing_cb);
                bt_app_hf_client_audio_open();
            } else if (param->audio_stat.state == ESP_HF_CLIENT_AUDIO_STATE_DISCONNECTED) {
                bt_app_hf_client_audio_close();
            }
    #endif /* #if CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_HCI */
            break;
        }
        case ESP_HF_CLIENT_BVRA_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--VR state %s",
                    c_vr_state_str[param->bvra.value]);
            break;
        }
        case ESP_HF_CLIENT_CIND_SERVICE_AVAILABILITY_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--NETWORK STATE %s",
                    c_service_availability_status_str[param->service_availability.status]);
            break;
        }
        case ESP_HF_CLIENT_CIND_ROAMING_STATUS_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--ROAMING: %s",
                    c_roaming_status_str[param->roaming.status]);
            break;
        }
        case ESP_HF_CLIENT_CIND_SIGNAL_STRENGTH_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "-- signal strength: %d",
                    param->signal_strength.value);
            break;
        }
        case ESP_HF_CLIENT_CIND_BATTERY_LEVEL_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--battery level %d",
                    param->battery_level.value);
            break;
        }
        case ESP_HF_CLIENT_COPS_CURRENT_OPERATOR_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--operator name: %s",
                    param->cops.name);
            break;
        }
        case ESP_HF_CLIENT_CIND_CALL_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--Call indicator %s",
                    c_call_str[param->call.status]);
            break;
        }
        case ESP_HF_CLIENT_CIND_CALL_SETUP_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--Call setup indicator %s",
                    c_call_setup_str[param->call_setup.status]);
            break;
        }
        case ESP_HF_CLIENT_CIND_CALL_HELD_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--Call held indicator %s",
                    c_call_held_str[param->call_held.status]);
            break;
        }
        case ESP_HF_CLIENT_BTRH_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--response and hold %s",
                    c_resp_and_hold_str[param->btrh.status]);
            break;
        }
        case ESP_HF_CLIENT_CLIP_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--clip number %s",
                    (param->clip.number == NULL) ? "NULL" : (param->clip.number));
            // 发送消息
            alert_ctrl_send_event(ALERT_ENENT_CALL_IN);
            break;
        }
        case ESP_HF_CLIENT_CCWA_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--call_waiting %s",
                    (param->ccwa.number == NULL) ? "NULL" : (param->ccwa.number));
            break;
        }
        case ESP_HF_CLIENT_CLCC_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--Current call: idx %d, dir %s, state %s, mpty %s, number %s",
                    param->clcc.idx,
                    c_call_dir_str[param->clcc.dir],
                    c_call_state_str[param->clcc.status],
                    c_call_mpty_type_str[param->clcc.mpty],
                    (param->clcc.number == NULL) ? "NULL" : (param->clcc.number));
            break;
        }
        case ESP_HF_CLIENT_VOLUME_CONTROL_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--volume_target: %s, volume %d",
                    c_volume_control_target_str[param->volume_control.type],
                    param->volume_control.volume);
            break;
        }
        case ESP_HF_CLIENT_AT_RESPONSE_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--AT response event, code %d, cme %d",
                    param->at_response.code, param->at_response.cme);
            break;
        }
        case ESP_HF_CLIENT_CNUM_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--subscriber type %s, number %s",
                    c_subscriber_service_type_str[param->cnum.type],
                    (param->cnum.number == NULL) ? "NULL" : param->cnum.number);
            break;
        }
        case ESP_HF_CLIENT_BSIR_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--inband ring state %s",
                    c_inband_ring_state_str[param->bsir.state]);
            break;
        }
        case ESP_HF_CLIENT_BINP_EVT:
        {
            ESP_LOGI(BT_HF_TAG, "--last voice tag number: %s",
                    (param->binp.number == NULL) ? "NULL" : param->binp.number);
            break;
        }
        default:
            ESP_LOGE(BT_HF_TAG, "HF_CLIENT EVT: %d", event);
            break;
    }
}

// 常驻任务
static void task_handler(void *arg)
{
    uint8_t event;
    bool is_connect = false;
    bool is_found = false;
    char last_time = 0;
    while (1) {
        // 读取消息队列 1s超时时间
        if (pdTRUE == xQueueReceive(task_queue, &event, 1000 / portTICK_PERIOD_MS)) {
            switch(event)
            {
                case 0x00:  // 蓝牙未连接
                    is_connect = false;
                    // 关闭扫描
                    esp_bt_gap_cancel_discovery();
                    // 开始发现附近的蓝牙设备 - 扫描时间 1.28*10秒(ranging from 0x01 to 0x30)
                    esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
                    break;
                case 0x01: // 蓝牙已连接
                    is_connect = true;
                    last_time = 0;
                    break;
                case 0x02: // 蓝牙开始扫描
                        is_found = false;
                    break;
                case 0x03: // 蓝牙扫描完成
                    // 如果没找到, 延时10秒继续开始扫描
                    if(!is_found) last_time = 10;
                    break;
                case 0x04: // 找到需要连接的设备
                        if(is_found) break;
                        is_found = true;
                        // 关闭扫描
                        esp_bt_gap_cancel_discovery();
                        // 连接
                        // 接口参考例程hfp_hf中的app_hf_msg_set.c
                        if(!is_connect) esp_hf_client_connect(peer_addr);
                    break;
            }
        }
        else
        {
            if(last_time) // 重连
            {
                printf("%d seconds to rediscover\n", last_time);
                last_time--;
                // 发送一个蓝牙未连接消息
                if(!last_time) hfp_app_send_event(0x00);
            }
        }
    }
}

static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);

// 初始化
void hfp_app_init()
{
    char *dev_name = "来电话提醒";
    esp_err_t err;

    // NVS里存储了PHY的校准数据 - 初始化蓝牙参数
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
        ESP_LOGE(BT_HF_TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }
    if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
        ESP_LOGE(BT_HF_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }
    if ((err = esp_bluedroid_init()) != ESP_OK) {
        ESP_LOGE(BT_HF_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }
    if ((err = esp_bluedroid_enable()) != ESP_OK) {
        ESP_LOGE(BT_HF_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
        return;
    }

    // 设置蓝牙名
    esp_bt_dev_set_device_name(dev_name);
    // 注册事件回调并初始化
    esp_hf_client_register_callback(bt_app_hf_client_cb);
    esp_hf_client_init();
    // 设置配对码
    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
    esp_bt_pin_code_t pin_code;
    pin_code[0] = '0';
    pin_code[1] = '0';
    pin_code[2] = '0';
    pin_code[3] = '0';
    esp_bt_gap_set_pin(pin_type, 4, pin_code);
    // 设置为可发现和可连接模式, 等待连接
    esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);

    // 读取最后连接的蓝牙mac
    my_nvs_read_mac(peer_addr);

    // 连接
    // 接口参考例程hfp_hf中的app_hf_msg_set.c
    // esp_hf_client_connect(peer_addr);

    // 创建队列用来通信
    task_queue = xQueueCreate(10, 1);
    // 创建一个常驻任务
    xTaskCreate(task_handler, "hfp_app_task", 2048, NULL, configMAX_PRIORITIES - 3, &task_handle);

    // 注册GAP回调函数
    esp_bt_gap_register_callback(bt_app_gap_cb);

    // 发送一个蓝牙未连接消息
    hfp_app_send_event(0x00);
}

static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
{
    if (bda == NULL || str == NULL || size < 18) {
        return NULL;
    }
    uint8_t *p = bda;
    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
            p[0], p[1], p[2], p[3], p[4], p[5]);
    return str;
}

// GAP回调函数 - 详见例程bt_discovery.c
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
    static bool is_discovery = false; 
    switch (event) {
    case ESP_BT_GAP_DISC_RES_EVT: {
        esp_bt_gap_dev_prop_t *p;
        char bda_str[18];
        uint32_t cod = 0;
        int32_t rssi = -129; // 这是个无效的值
        ESP_LOGI(BT_HF_TAG, "Device found: %s", bda2str(param->disc_res.bda, bda_str, 18));
        // 如果扫描到的是我们需要连接的设备, 则连接他
        if(!memcmp(param->disc_res.bda, peer_addr, sizeof(esp_bd_addr_t)))
        {
            // 发送一个找到蓝牙设备消息
            hfp_app_send_event(0x04);
        }
        for (int i = 0; i < param->disc_res.num_prop; i++) {
            p = param->disc_res.prop + i;
            switch (p->type) {
            case ESP_BT_GAP_DEV_PROP_COD:
                cod = *(uint32_t *)(p->val);
                ESP_LOGI(BT_HF_TAG, "--Class of Device: 0x%x", cod);
                break;
            case ESP_BT_GAP_DEV_PROP_RSSI:
                rssi = *(int8_t *)(p->val);
                ESP_LOGI(BT_HF_TAG, "--RSSI: %d", rssi);
                break;
            case ESP_BT_GAP_DEV_PROP_BDNAME:
            default:
                break;
            }
        }
        break;
    }
    case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
        if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
            ESP_LOGI(BT_HF_TAG, "Device discovery stopped."); //  这个事件会收到俩次, 不知道为什么，加个变量判断一下
            // 发送一个蓝牙扫描完成消息
            if(is_discovery) hfp_app_send_event(0x03);
            is_discovery = false; 
        } else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
            ESP_LOGI(BT_HF_TAG, "Discovery started.");
            is_discovery = true; 
            // 发送一个蓝牙开始扫描消息
            hfp_app_send_event(0x02);
        }
        break;
    }
    case ESP_BT_GAP_RMT_SRVCS_EVT:
    case ESP_BT_GAP_RMT_SRVC_REC_EVT:
    default: {
        ESP_LOGI(BT_HF_TAG, "event: %d", event);
        break;
    }
    }
    return;
}
